/* 종이천하 내맞춤쪽 Google Chrome Extension
   background.js
   v0.3:
   	- 댓글알림 + 전체새글 : done
   	- 전체새글의 경우, 최근 업데이트 시간 저장해서 그 이후만 불러오기 : done
   	- 불러온 댓글/글 조회없이 삭제 -> 연기 (현재apikey는 정보 조회만 가능)
   	- apikey 생성화면 링크 : done
   	- 프로파일 : 구버전 (done), 새버전[me]
   	- 쪽지 알림 : done
   	- 같은 탭 계속 사용 : done
   v0.36:
   	- 최근 업데이트 시간을 서버에서 관리: done
		newPosts
			total
			lastChecked*
			post
				group
				board
				title
				bo_table
				wr_id
				name
				datetime
   	
   	- 서버사이드 gcext.ajax.php 로 통합
   	- 새쪽지와 새댓글을 통합 리턴  (프로파일은 유지): done
	myPage*
		newMessages
			total
			message
				name
				content
				URL
				datetime
		newComments
			total
			comment
				group
				board
				title
				URL
				name
				datetime
   v.037:
   	- 새 쪽지/댓글 소리 알림 + desktop notification
   	
   v.038:
    - try on parsing in option.html by j2paper@papermodel.org --> didn't work with console
    - add watch board (for manager) - add 'watched' tag to newPosts (new.ajax.php) 
		newPosts
			total
			lastChecked
			post
				...
    			watched*
    -  and add 'watch list' in profile And the corresponding alarms can be controlled in option (post / commet)
		profile
			...
			watchBoards*

	v.040:
	 - not much new, but limit the total posts to 40 & fix false initialization
 */
var ajaxPath = "lab/ajax/";
var mMsec = 60*1000;
var hMsec = 60*60*1000;
var audioElement = new Audio();

function updateTitleBadge()
{
	var totalMessages = localStorage["totalMessages"];
	var unreadMessages = localStorage["unreadMessages"];
	var totalComments = localStorage["totalComments"];
	var unreadComments = localStorage["unreadComments"];
	var totalWatches  = localStorage["totalWatches"];
	var unreadWatches  = localStorage["unreadWatches"];
		
	//update title
	var title = "";
	if(totalComments==0 && totalMessages==0 && totalWatches==0) {
		title = "새 댓글/쪽지가 없습니다.";
	}else {
		if(totalComments>0) title = "새 댓글: " + totalComments;
		if(totalComments>0 && totalMessages>0) title = title + " & ";
		if(totalMessages>0) title = title + "새 쪽지: " + totalMessages;
		if(totalComments+totalMessages>0 && totalWatches>0) title = title + " & ";
		if(totalWatches>0) title = title + "새 관심: " + totalWatches;
		title = title + " 있습니다.";
	}
	chrome.browserAction.setTitle({ title: title });

	//update badge + alarm
	var badge = "";
	var colorR = 0;
	var colorG = 0;
	var colorB = 0;
	if(totalComments == 0 && totalMessages==0 && totalWatches==0) {
		badge = "";
	}else {
		// badge update
		if(totalComments>0) {
			badge = nK(totalComments);
			colorG = 255;
		}
		if(totalComments>0 && totalMessages>0) badge = badge + ":";
		if(totalMessages>0) {
			badge = badge + nK(totalMessages);
			colorB = 255;
		}
		if(totalComments+totalMessages>0 && totalWatches>0) badge = badge + ":";
		if(totalWatches>0) {
			badge = badge + nK(totalWatches);
			colorR = 255;
		}
		// alarm + notification
		if(totalMessages > unreadMessages || totalComments > unreadComments || totalWatches > unreadWatches) playSound();
		if(totalMessages > unreadMessages) showNotification('message', totalMessages-unreadMessages);
		if(totalComments > unreadComments) showNotification('comment', totalComments-unreadComments);
		if(totalWatches > unreadWatches) showNotification('watched', totalWatches-unreadWatches);

		localStorage["unreadMessages"] = totalMessages;
		localStorage["unreadComments"] = totalComments;
		localStorage["unreadWatches"] = totalWatches;
	}
	chrome.browserAction.setBadgeBackgroundColor({color:[colorR,colorG,colorB,255]});
	chrome.browserAction.setBadgeText({text:badge});	
}

function playSound() {
	if (localStorage["soundOn"] == null || localStorage["soundOn"] == "false")
		return;

	var source = localStorage["soundFile"];

	try {
		audioElement.src = source;
		audioElement.load();
		audioElement.play();
	} catch (e) {
//		console.error(e);
	}
}

function showNotification(type, nb) {
	if (localStorage["notifyOn"] == null || localStorage["notifyOn"] == "false")
		return;
	
	try {
		var title = "쪽지";
		var xml = localStorage["newMessages"];
		var context = "message"
		var target = "content";
		var condition = "";
		if(type=='comment') {
			title = "댓글";
			xml = localStorage["newComments"];
			context = "comment";
			target = "title";
		}else if(type=='watched'){
			title = "관심글";
			xml = localStorage["newPosts"];
			context = "post";
			target = "title";
			condition = "watched";
		}
		var element = findXMLelement(xml, context, condition);
		var name = element ? extractXMLelement(element, "name") : "";
		var content = element ? extractXMLelement(element, target) : "";
		var postfix = "";
		if(nb>1) postfix = " (총 " + nb + "개의 새 " + title + ")"; 
		var notification = webkitNotifications.createNotification(
			'finalpaper.png',		// The image.
			'새 ' + title + ' from ' + name,	// The title.
			content	+ postfix		// The body.
		);
		notification.show();
	} catch (e) {
//		console.error(e);
	}
}

function storageEventHandler(e)
{
	if(e.key=='totalComments' || e.key=='totalMessages' || e.key=='totalWatches') {
		updateTitleBadge();
	}
}
window.addEventListener('storage', storageEventHandler, false);

chrome.tabs.onRemoved.addListener(function(tabId) { 
	if(tabId==parseInt(localStorage["openedTabId"])) {
		localStorage["openedTabId"]="";
	}
});

function initLocalStorage()
{
	if(!localStorage["mb_id"]||!localStorage["apikey"]) {
		chrome.browserAction.setTitle({ title: "회원정보를 입력하세요." });
		chrome.browserAction.setBadgeBackgroundColor({color:[255,0,0,255]});
		chrome.browserAction.setBadgeText({text: "?"});
	}
	
	if(!localStorage["renewMyPage"]) localStorage["renewMyPage"] = "5";	// default 5mins
	if(!localStorage["renewMyProfile"]) localStorage["renewMyProfile"] = "60";	// default 1hour
	if(!localStorage["renewNewPost"]) localStorage["renewNewPost"] = "10";	// default 10mins

	localStorage["errorPost"] = "";
	localStorage["totalPosts"] = "0";
	localStorage["newPosts"] = "";
	localStorage["oldPosts"] = "";
	localStorage["lastChecked"] = "";
	if(!localStorage["watchBoards"]) localStorage["watchBoards"] = "";	// v0.38+: # of watched posts/comments (from the watched boards)
	localStorage["totalWatches"] = "0";	
	localStorage["unreadWatches"] = "0";

	localStorage["errorMyPage"] = "";
	localStorage["totalMessages"] = "0";
	localStorage["unreadMessages"] = "0";
	localStorage["newMessages"] = "";
	localStorage["totalComments"] = "0";
	localStorage["unreadComments"] = "0";
	localStorage["newComments"] = "";

	localStorage["profile"] = "";

	localStorage["openedTabId"] = "";
	
	if(!localStorage["soundOn"]) localStorage["soundOn"] = "true";
	localStorage["soundFile"] = "chime.mp3";
	if(!localStorage["notifyOn"]) localStorage["notifyOn"] = "true";
}

function requestMyPage()
{
	var mb_id  = localStorage["mb_id"];
  	var apikey = localStorage["apikey"];

	chrome.browserAction.setTitle({ title: "정보를 읽어옵니다." });
	chrome.browserAction.setBadgeBackgroundColor({color:[200,200,200,255]});
	chrome.browserAction.setBadgeText({text: "..."});
  	localStorage["errorMyPage"] = "";

	var xhr = new XMLHttpRequest();

	xhr.open("GET", "http://www.finalpaper.net/" + ajaxPath + "gcext.ajax.php?mb_id=" + mb_id + "&apikey=" + apikey, true);

	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			var resp = handleMyPageResponse(xhr.responseText);
		}
	}
	xhr.send();

	window.setTimeout(requestMyPage,parseInt(localStorage["renewMyPage"])*mMsec);
}

function handleMyPageResponse(xml)
{
	//get error if any
	if(xml.indexOf("<error>")!=-1) 
	{
		localStorage["errorMyPage"] = extractXMLelement(xml, "error");
		
		chrome.browserAction.setTitle({ title: "ERROR: " + message });
		chrome.browserAction.setBadgeBackgroundColor({color:[255,0,0,255]});
		chrome.browserAction.setBadgeText({text: "X"});
		localStorage["newComments"] = "";
		return;
	}
	
	//get # new posts
	if(xml.indexOf("<myPage>")!=-1)
	{
		localStorage["errorMyPage"] = "";
		
		var xmlMessages = extractXMLelement(xml, "newMessages");
		var total = extractXMLelement(xmlMessages, "total");
		localStorage["totalMessages"] = total;
		localStorage["newMessages"] = "<newMessages>"+xmlMessages+"</newMessages>";

		var xmlComments = extractXMLelement(xml, "newComments");
		var total = extractXMLelement(xmlComments, "total");
		localStorage["totalComments"] = total;
		localStorage["newComments"] = "<newComments>"+xmlComments+"</newComments>";

		updateTitleBadge();
	}
	handleMyPage();
}

function handleMyPage() {	// placeholder for real function in popup.html
}

function requestMyProfile()
{
	var mb_id  = localStorage["mb_id"];
  	var apikey = localStorage["apikey"];
  	localStorage["errorMyPage"] = "";

	var xhr = new XMLHttpRequest();

	xhr.open("GET", "http://www.finalpaper.net/" + ajaxPath + "gcext.ajax.php?mb_id=" + mb_id + "&apikey=" + apikey + "&profile=yes", true);

	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			var resp = handleProfileResponse(xhr.responseText);
		}
	}
	xhr.send();

	window.setTimeout(requestMyProfile,parseInt(localStorage["renewMyProfile"])*mMsec);
}

function handleProfileResponse(xml)
{
	//get error if any
	if(xml.indexOf("<error>")!=-1)
	{
		localStorage["errorMyPage"] = extractXMLelement(xml, "error");
	}
	
	//get profile
	if(xml.indexOf("<profile>")!=-1)
	{
		localStorage["profile"] = xml;
	}
	handleProfile();
}

function handleProfile() {	// placeholder for real function in option.html
}

function requestNewPosts()
{
	if(localStorage["newPosts"]) mergePosts();	// merge newPosts to oldPosts
	var lastChecked = localStorage["lastChecked"];
	var xhr = new XMLHttpRequest();

	if(!lastChecked) {
		xhr.open("GET", "http://www.finalpaper.net/" + ajaxPath + "new.ajax.php", true);
	}
	else {
		xhr.open("GET", "http://www.finalpaper.net/" + ajaxPath + "new.ajax.php?lastUpdated=" + lastChecked, true);
	}

	xhr.onreadystatechange = function() {
		if (xhr.readyState == 4) {
			var resp = handlePostResponse(xhr.responseText);
		}
	}
	xhr.send();

	window.setTimeout(requestNewPosts,parseInt(localStorage["renewNewPost"])*mMsec);
}	

function handlePostResponse(xml)
{
	//get error if any
	if(xml.indexOf("<error>")!=-1)
	{
		localStorage["errorPost"] = extractXMLelement(xml, "error");
		localStorage["newPosts"] = "";
	}
	
	//get # new posts
	if(xml.indexOf("<newPosts>")!=-1)
	{
		localStorage["errorPost"] = "";
		localStorage["totalPosts"] = extractXMLelement(xml, "total");
		localStorage["lastChecked"] = extractXMLelement(xml, "lastChecked");
		localStorage["newPosts"] = xml;

		updateWatchedStatus();
		updateTitleBadge();
	}
//	handleNewPosts();	// need to check if the tab is set for new post...
}

function handleNewPosts() {	// placeholder for real function in popup.html
}

function updateWatchedStatus(depth) {	// add or remove 'watched' tag based on lS['watchBoards']
	var watchPostBoards = new Array();
	var watchCommentBoards = new Array();
	var savedOptions = localStorage["watchBoards"].split(",");
	for(var j=0; j<savedOptions.length; j++) {
		var options = savedOptions[j].split(':');
		if(options[1] & 1) watchPostBoards.push(options[0]);
		if(options[1] & 2) watchCommentBoards.push(options[0]);
	}
	var totalWatches = localStorage["totalWatches"];
	
	var parser=new DOMParser();
	if(localStorage["newPosts"]) {
		var xmlDoc=parser.parseFromString(localStorage["newPosts"],"text/xml");
		var search = xmlDoc.getElementsByTagName("post");
		for(var i=0; i<search.length; i++) {
			
			if( ( (search[i].getElementsByTagName("title")[0].childNodes[0].nodeValue.indexOf('[코]')==-1	// post
					&& watchPostBoards.indexOf(search[i].getElementsByTagName("bo_table")[0].childNodes[0].nodeValue)!=-1)	// post in watched boards
				||(search[i].getElementsByTagName("title")[0].childNodes[0].nodeValue.indexOf('[코]')!=-1	// comment
					&& watchCommentBoards.indexOf(search[i].getElementsByTagName("bo_table")[0].childNodes[0].nodeValue)!=-1)	// comment in watched boards
				) ^ search[i].getElementsByTagName("watched").length>0 ) 
				{
				if(search[i].getElementsByTagName("watched").length>0) {
					search[i].removeChild(search[i].getElementsByTagName("watched")[0]);
					totalWatches--;
				}
				else {
					var watched = document.createElement("watched","");
					watched.innerHTML = "*";
					search[i].appendChild(watched);
					totalWatches++;
				}
			}
		}
		localStorage["newPosts"] = (new XMLSerializer()).serializeToString(xmlDoc);
	}
	
	// check oldPosts
	if(depth=="old" && localStorage["oldPosts"]) {		// only update when watch board option changed
		var xmlDoc=parser.parseFromString(localStorage["oldPosts"],"text/xml");
		var search = xmlDoc.getElementsByTagName("post");
		for(var i=0; i<search.length; i++) {
			
			if( ( (search[i].getElementsByTagName("title")[0].childNodes[0].nodeValue.indexOf('[코]')==-1	// post
					&& watchPostBoards.indexOf(search[i].getElementsByTagName("bo_table")[0].childNodes[0].nodeValue)!=-1)	// post in watched boards
				||(search[i].getElementsByTagName("title")[0].childNodes[0].nodeValue.indexOf('[코]')!=-1	// comment
					&& watchCommentBoards.indexOf(search[i].getElementsByTagName("bo_table")[0].childNodes[0].nodeValue)!=-1)	// comment in watched boards
				) ^ search[i].getElementsByTagName("watched").length>0 ) 
				{
				if(search[i].getElementsByTagName("watched").length>0) {
					search[i].removeChild(search[i].getElementsByTagName("watched")[0]);
					totalWatches--;
				}
				else {
					var watched = document.createElement("watched","");
					watched.innerHTML = "*";
					search[i].appendChild(watched);
					totalWatches++;
				}
			}
		}
		localStorage["oldPosts"] = (new XMLSerializer()).serializeToString(xmlDoc);
	}
	
	localStorage["totalWatches"] =  totalWatches;
}

function mergePosts()
{
	// merge newPosts to oldPosts
/*
	DOM structure:
		newPosts
			total
			post
		
		oldPosts
			post
*/
	var limitLength = 60;
	var parser=new DOMParser();

	var newXml = parser.parseFromString(localStorage["newPosts"],"text/xml");
	var postviews = newXml.getElementsByTagName("post");
	if(localStorage["oldPosts"])
	{
		var oldXml = parser.parseFromString(localStorage["oldPosts"],"text/xml");
		
		// insert newPosts
		var insertPosition = oldXml.getElementsByTagName("post")[0];
		for(var i=0; postviews.length>0; i++)
		{
			oldXml.documentElement.insertBefore(postviews[0],insertPosition);
		}
	}
	else
	{
		var oldXml = parser.parseFromString("<oldPosts><total>0</total></oldPosts>","text/xml");
		for(var i=0; postviews.length>0; i++)
		{
			oldXml.documentElement.appendChild(postviews[0]);	// actually moving the first postview to oldXml
		}
	}

	// limit the total length of old 
	var oldviews = oldXml.getElementsByTagName("post");
	while(oldviews.length>limitLength)
	{
		oldviews[limitLength].parentNode.removeChild(oldviews[limitLength]);
	}
	
	localStorage["oldPosts"] = (new XMLSerializer()).serializeToString(oldXml);
	localStorage["newPosts"] = "";
}

// utility functions
function nK(number)	// 1k = 1001~1999, 2k = 2001 ~ 2999 so on
{
	var formatedNumber = number;
	if(number > 1000) {
		formatedNumber = (number/1000) | 0;
		formatedNumber = badge + "k";
	}
	return formatedNumber;
}

function extractXMLelement(str,tag)		// extract the content inside the first TAG	
{
	var start = str.indexOf("<"+tag+">") + tag.length + 2;
	var end   = str.indexOf("</"+tag+">");
	return str.substring(start,end);
}

function findXMLelement(str,tag,con)		// find the first TAG
											// v0.38+ added con(dition): e.g. select the first 'post' which has 'watched'
{
	var parser=new DOMParser();
	var xmlDoc=parser.parseFromString(str,"text/xml");
	var els = xmlDoc.getElementsByTagName(tag);
	var length = els.length;
	if(!length) return "";	// not matched tag

	for(var i=0; i<length; i++) {
		if(!con || els[i].getElementsByTagName(con).length) {
			return (new XMLSerializer()).serializeToString(els[i]);
		}
	}		
	return "";	// not matched with condition
}

function findXMLelements(str,tag,con)	// find the the TAG with conditional CON tag
{
	var rets = new Array();
	
	var parser=new DOMParser();
	var xmlDoc=parser.parseFromString(str,"text/xml");
	var els = xmlDoc.getElementsByTagName(tag);
	var length = els.length;
	if(length) {
		for(var i=0; i<length; i++) {
			if(!con || els[i].getElementsByTagName(con).length) {
				rets.push( (new XMLSerializer()).serializeToString(els[i]) );
			}
		}		
	}
	return rets;
}

function leadingZero(number) 
{
	return number < 10 ? "0" + number : number;
}

function formatDate(oldDate) {	// no need anymore.. but just keeping just for formatting
    var date = new Date(oldDate.getTime() + parseInt(localStorage["timeOffset"]) * 3600000);
    return date.getFullYear() + "-" + 
        leadingZero(date.getMonth()+1) + "-"+
        leadingZero(date.getDate()) + "+" + 
        leadingZero(date.getHours()) + ":" + 
        leadingZero(date.getMinutes()) + ":" +
        leadingZero(date.getSeconds());
}
